home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / ng_clone.zip / NG_CLONE.PAS < prev    next >
Pascal/Delphi Source File  |  1990-02-21  |  50KB  |  1,510 lines

  1. {$M 4096,0,0}                 {Reduce stack and heap}
  2. {$R-,I-}                      {Cut off range and I/O checking}
  3.   
  4. program ng_clone;
  5. {After all, that's what it is; Thank you, Mr. Norton, you are among my heroes!}
  6.   
  7. uses    crt,tesstp5;
  8. {TESS version MUST match compiler version}
  9.   
  10. type
  11.   
  12.   gentry=record         {General entry type}
  13.     filptr:longint;
  14.     name:string[40];
  15.   end;
  16.   
  17.   textel= record        {Text-mode screen element}
  18.     cha:byte;
  19.     att:byte;
  20.   end;
  21.   
  22.   fiftylinebuf= array[1..50,1..80] of textel;   {Video buffer types}
  23.   twelwebuf=    array[1..12,1..80] of textel;
  24.   savedline=    array[1..80] of textel;
  25.   
  26. var
  27.   screen:fiftylinebuf absolute $B800:$0000;     {Text-mode screen,     }
  28.                                                 {should be B000:0000h  }
  29.                                                 {on monochrome         }
  30.   csr:word absolute $0040:$0060;                {Low-memory cursor info}
  31.   screenmode:word absolute $0040:$0049;         {Low-memory screen info}
  32.   numrows:word absolute $0040:$0084;            {Low-memory screen info}
  33.   savedscreen:fiftylinebuf;                     {Buffer save current screen on entry}
  34.   smallscreen:twelwebuf;                        {Buffer holds screen template}
  35.   menuline:array[0..1] of savedline;            {Buffer screen template}
  36.   largescreen:array[0..1] of savedline;         {Buffer screen template}
  37.   scrollbuffer:array[0..511] of string[84];     {Buffer guide text entry}
  38.   infobuffer:array[0..511] of longint;          {Buffer guide file info}
  39.   seealso:array[0..19] of gentry;               {Buffer guide file info}
  40.   menu:array[0..2] of string[9]; {Buffer to hold static part of guide menu structure}
  41.   mennu:array[0..3,0..8] of gentry;  {Buffer to hold variable part of guide menu structure}
  42.   backstack:array[0..3] of byte;                {TESS background stack}
  43.   itemlist:array[0..3] of byte;                 {Menu structure info}
  44.   menuplaces,menulengths:array[0..6] of byte;   {Stacks for nested menu structures}
  45.   errorinfo:array[3..6] of string[14];          {Buffer for error messages}
  46.   f:file;                                                                                    {The guide file}
  47.   propath,homedir,streng:string;                {String variables, mostly for path and file use}
  48.   tsrstring:string[8];                          {TESS ID string}
  49.   parent:array[0..3] of longint;                {Stack for nested menu structures}
  50.   poffset:array[0..3] of word;                  {Stack for nested menu structures}
  51.   pcurpos:array[0..3] of byte;                  {Stack for nested menu structures}
  52.   defptr,stackptr:pointer;                      {TESS pointers}
  53.   previous,next:longint;                        {Previous and next entry}
  54.   idnum,i,j,offset,ch,id,bufferlength,savedcsr:word;        {Word variables}
  55.   erro,wix,wiy,curpos,entrytype,seealsonum,sapos,level,scrtypeflag,startline,
  56.   txtattri,
  57. Normal_Text,
  58. UnderScore,
  59. Bold_Face,
  60. Select_Cursor,
  61. Menu_Text,
  62. mlevel,xchoice,ychoice,menux,menuy,menuantal,menunr:byte;        {Byte variables}
  63.   
  64. procedure hidecrsr; {Make cursor invisible on CGA,EGA or VGA}
  65. begin
  66.   inline($B4/$01/$B5/$20/$CD/$10);
  67. end;
  68.   
  69. function restorecrsr(crsr:word):boolean;
  70.   {Restore saved cursor on CGA,EGA or VGA}
  71.   inline($B4/$01/$59/$CD/$10);
  72.   
  73.   function key:word;                                                                    {Keyboard interrupt}
  74.     inline($CD/$16);
  75.   
  76.     procedure keyread(var karakter:word);
  77.     {Readkey replacement}
  78.       var tch:char;
  79.     begin
  80.       karakter:=key;
  81.       if (lo(karakter)=0) then {If extended key, add 256 to value of key code}
  82.         begin
  83.           tch:=char(hi(karakter));
  84.           karakter:=ord(tch)+256;
  85.         end
  86.       else {Else return key code as is}
  87.         begin
  88.           tch:=char(lo(karakter));
  89.           karakter:=ord(tch);
  90.         end;
  91.     end;
  92.   
  93.     procedure writestring(cux,cuy,startattr,change,extra:byte;cus:string);        {Direct screen write}
  94.       var jcount,ycount,tmpchr:byte;
  95.         jch:char;
  96.     begin
  97.       jcount:=0;ycount:=0;txtattri:=startattr;
  98.       repeat
  99.         inc(jcount);
  100.         jch:=cus[jcount];
  101.         if jch<>'^' then       {If not NG control code, write character as is}
  102.           begin
  103.             if jch=#255 then   {Expand spaces}
  104.               begin
  105.                 inc(jcount);
  106.                 jch:=cus[jcount];
  107.                 for ycount:=ycount to ycount+ord(jch) do
  108.                   begin
  109.                     screen[cuy,cux+ycount].cha:=32;
  110.                     screen[cuy,cux+ycount].att:=txtattri;
  111.                   end;
  112.               end
  113.             else
  114.               begin
  115.                 screen[cuy,cux+ycount].cha:=ord(jch);
  116.                 screen[cuy,cux+ycount].att:=txtattri;
  117.                 inc(ycount);
  118.               end;
  119.           end
  120.         else                                                                            {Control code found!}
  121.           begin
  122.             inc(jcount);
  123.             jch:=cus[jcount];
  124.             if ((jch='A') or (jch='a')) then    {Color attribute command}
  125.               begin
  126.                 inc(jcount);
  127.                 jch:=cus[jcount];
  128.                 if change=1 then
  129.                   begin
  130.                     if ((ord(jch)>47) and (ord(jch)<58)) then txtattri:=ord(jch)-48 else
  131.                       if ((ord(jch)>64) and (ord(jch)<71)) then txtattri:=ord(jch)-55;
  132.                     txtattri:=16*txtattri;
  133.                   end;
  134.                 inc(jcount);
  135.                 jch:=cus[jcount];
  136.                 if change=1 then
  137.                   begin
  138.                     if ((ord(jch)>47) and (ord(jch)<58)) then txtattri:=txtattri+ord(jch)-48 else
  139.                       if ((ord(jch)>64) and (ord(jch)<71)) then txtattri:=txtattri+ord(jch)-55;
  140.                   end;
  141.               end
  142.             else if ((jch='C') or (jch='c')) then        {Difficult character}
  143.               begin
  144.                 inc(jcount);
  145.                 jch:=cus[jcount];
  146.                 if ((ord(jch)>47) and (ord(jch)<58)) then tmpchr:=ord(jch)-48 else
  147.                   if ((ord(jch)>64) and (ord(jch)<71)) then tmpchr:=ord(jch)-55;
  148.                 tmpchr:=16*tmpchr;
  149.                 inc(jcount);
  150.                 jch:=cus[jcount];
  151.                 if ((ord(jch)>47) and (ord(jch)<58)) then tmpchr:=tmpchr+ord(jch)-48 else
  152.                   if ((ord(jch)>64) and (ord(jch)<71)) then tmpchr:=tmpchr+ord(jch)-55;
  153.                 screen[cuy,cux+ycount].cha:=tmpchr;
  154.                 screen[cuy,cux+ycount].att:=txtattri;
  155.                 inc(ycount);
  156.               end
  157.             else if ((jch='b') or (jch='B')) then        {Boldface (?)}
  158.               begin
  159.                 if change=1 then
  160.                   begin
  161.                     if txtattri=Normal_Text then txtattri:=Bold_Face else txtattri:=Normal_Text;
  162.                   end;
  163.               end
  164.             else if ((jch='u') or (jch='U')) then        {Underline (?)}
  165.               begin
  166.                 if change=1 then
  167.                   begin
  168.                     if txtattri=Normal_Text then txtattri:=UnderScore else txtattri:=Normal_Text;
  169.                   end;
  170.               end
  171.             else if jch='^' then              {Write control character itself}
  172.               begin
  173.                 screen[cuy,cux+ycount].cha:=ord(jch);
  174.                 screen[cuy,cux+ycount].att:=txtattri;
  175.                 inc(ycount);
  176.               end;
  177.           end;
  178.       until jcount>=length(cus);
  179.       if extra>0 then                           {If desired, fill with blanks}
  180.         begin
  181.           while ycount<extra do
  182.             begin
  183.               screen[cuy,cux+ycount].cha:=32;
  184.               screen[cuy,cux+ycount].att:=txtattri;
  185.               inc(ycount);
  186.             end;
  187.         end;
  188.     end;
  189.   
  190.     procedure threenitvars;                      {Initialize variables}
  191.     begin
  192.       menunr:=0;
  193.       level:=0;
  194.       curpos:=0;
  195.       offset:=0;
  196.       menux:=3;
  197.       menuy:=0;
  198.       mlevel:=0;
  199.       xchoice:=0;
  200.       ychoice:=0;
  201.       sapos:=0;
  202.       wix:=0;wiy:=0;
  203.       txtattri:=Normal_Text;
  204.     end;
  205.   
  206.     procedure twonitvars;                        {Initialize variables}
  207.     begin
  208.       threenitvars;
  209.       menuplaces[0]:=5;
  210.       menuplaces[1]:=15;
  211.       menuplaces[2]:=28;
  212.       menuplaces[3]:=39;
  213.       menuplaces[4]:=0;
  214.       menuplaces[5]:=0;
  215.       menuplaces[6]:=0;
  216.       menulengths[0]:=20;
  217.       menulengths[1]:=20;
  218.       menulengths[2]:=20;
  219.       menulengths[3]:=0;
  220.       menulengths[4]:=0;
  221.       menulengths[5]:=0;
  222.       menulengths[6]:=0;
  223.       for j:=2 to 79 do smallscreen[1,j].cha:=205;
  224.       for j:=2 to 79 do smallscreen[2,j].cha:=0;
  225.     end;
  226.   
  227.     procedure initvars;
  228.     {Initialize variables}
  229.  
  230.       var str5:string;
  231.  
  232.     begin
  233.       Normal_Text:= 27;         {Color attribute for normal text}
  234.       UnderScore:= 126;         {Color attribute for underline}
  235.       Bold_Face:= 30;           {Color attribute for boldface}
  236.       Select_Cursor:= 48;       {Cursor color attribute}
  237.       Menu_Text := 30;          {Color attribute for Menu Text }
  238.       startline:=0;
  239.       scrtypeflag:=0;
  240.       twonitvars;
  241.       errorinfo[3]:='File not found';
  242.       errorinfo[4]:='Not an NG file';
  243.       errorinfo[5]:='Unexpected EOF';
  244.       errorinfo[6]:='Corrupted file';
  245.       menu[0]:='Expand';
  246.       menu[1]:='Search...';
  247.       menu[2]:='Options';
  248.       str5:='';propath:=paramstr(0);
  249.       while (pos('\',propath)>0) do
  250.         begin
  251.           str5:=str5+copy(propath,1,pos('\',propath));
  252.           propath:=copy(propath,pos('\',propath)+1,length(propath)-(pos('\',propath)+1));
  253.         end;
  254.       propath:=str5;
  255.     end;
  256.   
  257.     procedure initscreen;
  258.     {Read screen template from disk}
  259.       var sf:file;
  260.         numread:word;
  261.     begin
  262.       assign(sf,propath+'ng_clone.scr');
  263.       reset(sf,1);
  264.       blockread(sf,smallscreen,sizeof(smallscreen),numread);
  265.       blockread(sf,menuline[1],sizeof(menuline[1]),numread);
  266.       for i:=1 to 80 do largescreen[0,i]:=smallscreen[5,i];
  267.       for i:=1 to 80 do largescreen[1,i]:=smallscreen[11,i];
  268.       close(sf);
  269.     end;
  270.   
  271.     procedure removecursor;
  272.     {Next follows different cursor procedures}
  273.       var sl:byte;
  274.     begin
  275.       if scrtypeflag=0 then sl:=startline else sl:=0;
  276.       writestring(2,4+curpos+sl,Normal_Text,1,78,scrollbuffer[curpos+offset]);
  277.     end;
  278.   
  279.     procedure insertcursor;
  280.     {Another cursor procedure}
  281.       var sl:byte;
  282.     begin
  283.       if scrtypeflag=0 then sl:=startline else sl:=0;
  284.       writestring(2,4+curpos+sl,Select_Cursor,0,78,scrollbuffer[curpos+offset]);
  285.     end;
  286.   
  287.     procedure removemenucursor;
  288.     {Another cursor procedure}
  289.       var sl:byte;
  290.         cursor:string[78];
  291.     begin
  292.       if scrtypeflag=0 then sl:=startline else sl:=0;
  293.       if menux>2 then cursor:=' '+mennu[menux-3,0].name+' ' else
  294.         cursor:=' '+menu[menux]+' ';
  295.       writestring(menuplaces[menux]-1,2+sl,txtattri,0,0,cursor);
  296.     end;
  297.   
  298.     procedure insertmenucursor;
  299.     {Another cursor procedure}
  300.     begin
  301.       txtattri:=Select_Cursor;
  302.       removemenucursor;
  303.       txtattri:=Normal_Text;
  304.     end;
  305.   
  306.     procedure movemenucursor(direction:byte);
  307.     {Another cursor procedure}
  308.       var sl:byte;
  309.     begin
  310.       if ((entrytype=1) or (level=0)) then
  311.         begin
  312.           if scrtypeflag=0 then sl:=startline else sl:=0;
  313.           txtattri:=Bold_Face;
  314.           removemenucursor;
  315.           if direction=0 then
  316.             begin
  317.               if menux>0 then dec(menux) else menux:=2+menuantal;
  318.             end
  319.           else
  320.             begin
  321.               if menux<2+menuantal then inc(menux) else menux:=0;
  322.             end;
  323.           insertmenucursor;
  324.           for j:=1 to 80 do menuline[0][j]:=screen[2+sl,j];
  325.         end;
  326.     end;
  327.   
  328.     procedure removemlcursor;
  329.     {Another cursor procedure}
  330.       var    cursor:string[78];
  331.     begin
  332.       if ((menux-3=xchoice) and (menuy=ychoice)) then cursor:=#251+' '+mennu[menux-3,menuy+1].name else
  333.         cursor:='  '+mennu[menux-3,menuy+1].name;
  334.       while length(cursor)<menulengths[menux]+3 do cursor:=cursor+' ';
  335.       writestring(2+wix,2+menuy+wiy,txtattri,0,0,cursor);
  336.     end;
  337.   
  338.     procedure insertmlcursor;
  339.     {Another cursor procedure}
  340.     begin
  341.       txtattri:=Select_Cursor;
  342.       removemlcursor;
  343.       txtattri:=Normal_Text;
  344.     end;
  345.   
  346.     procedure removeseealso;
  347.     {Another cursor procedure}
  348.       var addo,sl:byte;
  349.         cursor:string[78];
  350.     begin
  351.       addo:=0;
  352.       if scrtypeflag=0 then sl:=startline else sl:=0;
  353.       for j:=0 to sapos do
  354.         begin
  355.           if j>0 then inc(addo,length(seealso[j-1].name)+2);
  356.         end;
  357.       cursor:=' '+seealso[sapos].name+' ';
  358.       writestring(13+addo,2+sl,txtattri,0,0,cursor);
  359.     end;
  360.   
  361.     procedure insertseealso;
  362.     {Another cursor procedure}
  363.     begin
  364.       txtattri:=Select_Cursor;
  365.       removeseealso;
  366.       txtattri:=Normal_Text;
  367.     end;
  368.   
  369.     procedure moveseealso(direction:byte);
  370.     {Another cursor procedure}
  371.     begin
  372.       if seealsonum<>255 then
  373.         begin
  374.           removeseealso;
  375.           if direction=0 then
  376.             begin
  377.               if sapos>0 then dec(sapos) else sapos:=seealsonum;
  378.             end
  379.           else
  380.             begin
  381.               if sapos<seealsonum then inc(sapos) else sapos:=0;
  382.             end;
  383.           insertseealso;
  384.         end;
  385.     end;
  386.   
  387.     procedure frame1(w,d:byte);
  388.    {Frame of line-drawing charcters used for menu}
  389.     begin
  390.       writestring(wix+1,wiy+1,Normal_Text,0,0,'┬');
  391.       for i:=2 to d-1 do
  392.         begin
  393.           writestring(1+wix,i+wiy,Normal_Text,0,0,'│');
  394.           writestring(w+wix,i+wiy,Normal_Text,0,0,'│');
  395.         end;
  396.       writestring(wix+1,wiy+d,Normal_Text,0,0,'└');
  397.       for i:=2 to w-1 do writestring(wix+i,wiy+d,Normal_Text,0,0,'─ ');
  398.       writestring(wix+i+1,wiy+1,Normal_Text,0,0,'┬');
  399.       writestring(wix+i+1,wiy+d,Normal_Text,0,0,'┘');
  400.     end;
  401.   
  402.     procedure createsmall;
  403.     {Save current screen and create small screen}
  404.     begin
  405.       savedscreen:=screen;
  406.       hidecrsr;
  407.       for i:=1 to 12 do
  408.         for j:=1 to 80 do
  409.           screen[i+startline,j]:=smallscreen[i,j];
  410.       writestring(5,2+startline,Bold_Face,0,0,menu[0]);
  411.       writestring(15,2+startline,Bold_Face,0,0,menu[1]);
  412.       writestring(28,2+startline,Bold_Face,0,0,menu[2]);
  413.       writestring(39,2+startline,Bold_Face,0,0,mennu[0,0].name);
  414.       if menuantal>1 then
  415.         begin
  416.           i:=length(mennu[0,0].name);
  417.           menuplaces[4]:=43+i;
  418.           writestring(43+i,2+startline,Bold_Face,0,0,mennu[1,0].name);
  419.         end;
  420.       if menuantal>2 then
  421.         begin
  422.           inc(i,length(mennu[1,0].name));
  423.           menuplaces[5]:=47+i;
  424.           writestring(47+i,2+startline,Bold_Face,0,0,mennu[2,0].name);
  425.         end;
  426.       if menuantal>3 then
  427.         begin
  428.           inc(i,length(mennu[2,0].name));
  429.           menuplaces[6]:=51+i;
  430.           writestring(51+i,2+startline,Bold_Face,0,0,mennu[3,0].name);
  431.         end;
  432.       i:=0;
  433.       while ((i<bufferlength+1) and (i<8)) do
  434.         begin
  435.           writestring(2,4+i+startline,Normal_Text,1,78,scrollbuffer[i]);inc(i);
  436.         end;
  437.       for i:=1 to 12 do
  438.         for j:=1 to 80 do
  439.           smallscreen[i,j]:=screen[i+startline,j];
  440.       insertmenucursor;
  441.       screen[5+startline,80].att:=$40;
  442.       for j:=1 to 80 do menuline[0][j]:=screen[2+startline,j];
  443.     end;
  444.   
  445.     procedure blank(width,height:byte);       {Blank part of screen}
  446.     begin
  447.       for i:=2 to height do for j:=1 to width do
  448.           begin
  449.             screen[wiy+i,wix+j].att:=Normal_Text;
  450.             screen[wiy+i,wix+j].cha:=0;
  451.           end;
  452.     end;
  453.   
  454.     procedure makemenu(num:byte);             {Make pull-down menu}
  455.       var windstart,sl:byte;
  456.     begin
  457.       if scrtypeflag=0 then sl:=startline else sl:=0;
  458.       if (menulengths[num]+menuplaces[num]+5>79) then
  459.         windstart:=79-(menulengths[num]+5)
  460.       else
  461.         windstart:=menuplaces[num]-2;
  462.       wix:=windstart-1;wiy:=2+sl;
  463.       blank(menulengths[num]+4,itemlist[num-3]+1);
  464.       frame1(menulengths[num]+5,1+itemlist[num-3]);
  465.       for i:=1 to itemlist[num-3]-1 do
  466.         begin
  467.           writestring(4+wix,1+i+wiy,Normal_Text,0,0,mennu[num-3,i].name);
  468.         end;
  469.       if num-3=xchoice then
  470.         begin
  471.           writestring(2+wix,2+ychoice+wiy,Normal_Text,0,0,#251);
  472.         end;
  473.       insertmlcursor;
  474.       mlevel:=1;
  475.     end;
  476.   
  477.     procedure writeseealsos(possible_offset:byte);
  478.     {Write seealso entries}
  479.       var satmp:word;
  480.     begin
  481.       if seealsonum<>255 then
  482.         begin
  483.           j:=0;satmp:=0;
  484.           for i:=0 to seealsonum do
  485.             begin
  486.               writestring(14+j,2+possible_offset,Normal_Text,0,0,seealso[i].name);
  487.               inc(j,length(seealso[i].name)+2);
  488.               if i<seealsonum then
  489.                 begin
  490.                   if (15+j+length(seealso[i+1].name)>79) then
  491.                     begin
  492.                       satmp:=i;
  493.                       i:=seealsonum;
  494.                     end
  495.                   else satmp:=0;
  496.                 end;
  497.             end;
  498.           if satmp>0 then seealsonum:=satmp;
  499.           insertseealso;
  500.         end;
  501.     end;
  502.   
  503.     procedure makesmall(vertical_offset:byte);
  504.     {Repaint small screen}
  505.     begin
  506.       if ((entrytype=1) or (level=0)) then
  507.         begin
  508.           for i:=1 to vertical_offset do
  509.             for j:=1 to 80 do screen[i,j]:=savedscreen[i,j];
  510.           for j:=1 to 80 do screen[vertical_offset+1,j]:=smallscreen[1,j];
  511.           for j:=1 to 80 do screen[vertical_offset+2,j]:=menuline[0][j];
  512.           for i:=3 to 12 do
  513.             for j:=1 to 80 do screen[i+vertical_offset,j]:=smallscreen[i,j];
  514.           for i:=(13+vertical_offset) to lo(numrows)+1 do
  515.             for j:=1 to 80 do screen[i,j]:=savedscreen[i,j];
  516.         end
  517.       else
  518.         begin
  519.           for i:=1 to vertical_offset do
  520.             for j:=1 to 80 do
  521.               screen[i,j]:=savedscreen[i,j];
  522.           for j:=1 to 80 do
  523.             screen[vertical_offset+1,j]:=smallscreen[1,j];
  524.           for j:=1 to 80 do
  525.             screen[vertical_offset+2,j]:=menuline[1][j];
  526.           for i:=3 to 12 do
  527.             for j:=1 to 80 do
  528.               screen[i+vertical_offset,j]:=smallscreen[i,j];
  529.           for i:=(13+vertical_offset) to lo(numrows)+1 do
  530.             for j:=1 to 80
  531.               do screen[i,j]:=savedscreen[i,j];
  532.           writeseealsos(vertical_offset);
  533.         end;
  534.       if entrytype=1 then
  535.         begin
  536.           if curpos>7 then
  537.             begin
  538.               inc(offset,curpos-7);
  539.               curpos:=7;
  540.             end;
  541.         end;
  542.       if entrytype=1 then insertcursor;
  543.       for i:=5 to 10 do
  544.         screen[i+vertical_offset,80].att:=$07;
  545.       i:=(((curpos+offset)*6) div (bufferlength+1))+5;
  546.       if i>10 then i:=10;
  547.       screen[i+vertical_offset,80].att:=$40;
  548.     end;
  549.   
  550.     procedure makelarge;
  551.     {Repaint large screen}
  552.       var    add:byte;
  553.     begin
  554.       if ((entrytype=1) or (level=0)) then
  555.         begin
  556.           for j:=1 to 80 do
  557.             screen[1,j]:=smallscreen[1,j];
  558.           for j:=1 to 80
  559.             do screen[2,j]:=menuline[0][j];
  560.           for i:=3 to 10
  561.             do for j:=1 to 80 do screen[i,j]:=smallscreen[i,j];
  562.           for i:=11 to lo(numrows)-1 do
  563.             for j:=1 to 80 do
  564.               screen[i,j]:=largescreen[0,j];
  565.           for j:=1 to 80 do
  566.             screen[lo(numrows),j]:=largescreen[1,j];
  567.           for j:=1 to 80 do
  568.             screen[lo(numrows)+1,j]:=smallscreen[12,j];
  569.         end
  570.       else
  571.         begin
  572.           for j:=1 to 80 do
  573.             screen[1,j]:=smallscreen[1,j];
  574.           for j:=1 to 80 do
  575.             screen[2,j]:=menuline[1][j];
  576.           for i:=3 to 10 do
  577.             for j:=1 to 80
  578.               do screen[i,j]:=smallscreen[i,j];
  579.           for i:=11 to lo(numrows)-1 do
  580.             for j:=1 to 80 do
  581.               screen[i,j]:=largescreen[0,j];
  582.           for j:=1 to 80 do
  583.             screen[lo(numrows),j]:=largescreen[1,j];
  584.           for j:=1 to 80 do
  585.             screen[lo(numrows)+1,j]:=smallscreen[12,j];
  586.           writeseealsos(0);
  587.         end;
  588.       if offset+lo(numrows)-4>bufferlength then
  589.         begin
  590.           if bufferlength>offset+lo(numrows)-4 then
  591.             begin
  592.               add:=offset-bufferlength+lo(numrows)-4;
  593.               inc(curpos,add);
  594.               offset:=bufferlength-lo(numrows)+4;
  595.             end
  596.           else
  597.             begin
  598.               inc(curpos,offset);
  599.               offset:=0;
  600.             end;
  601.         end;
  602.       i:=0;
  603.       while ((i+offset<bufferlength+1) and (i<lo(numrows)-3)) do
  604.         begin
  605.           writestring(2,4+i,Normal_Text,1,78,scrollbuffer[i+offset]);inc(i);
  606.         end;
  607.       if i<lo(numrows)-3 then for i:=i to lo(numrows)-4 do
  608.           begin
  609.             writestring(2,4+i,Normal_Text,0,78,' ');
  610.           end;
  611.       if entrytype=1 then
  612.         begin
  613.           if curpos>7 then add:=curpos-7 else add:=0;
  614.         end
  615.       else
  616.         begin
  617.           add:=0;
  618.         end;
  619.       for i:=4 to 11 do for j:=2 to 79 do smallscreen[i,j]:=screen[i+add,j];
  620.       if entrytype=1 then insertcursor;
  621.       for i:=5 to lo(numrows)-1 do screen[i,80].att:= 27;
  622.       i:=(((curpos+offset)*(lo(numrows)-5)) div (bufferlength+1))+5;
  623.       if i>lo(numrows)-1 then i:=lo(numrows)-1;
  624.       screen[i,80].att:=$40;
  625.       if mlevel=1 then makemenu(menux);
  626.     end;
  627.   
  628.     procedure usage;
  629.     {Write usage info}
  630.     begin
  631.       writeln('NG_CLONE USAGE   :');
  632.       writeln('──────────────────');
  633.       writeln;
  634.       writeln('  ng_clone <'+#123+'d:\dir\'+#125+'file'+#123+'.ext'+#125+'> '+#123+
  635.       '<d:\ngdir>'+#125+' <+/->  :run NG_CLONE (see below)');
  636.       writeln('  ng_clone </u> or </U>                           :remove NG_CLONE if resident');
  637.       writeln('  ng_clone </?> or </h> or </H>                   :show this usage information');
  638.       writeln;
  639.       writeln('  The +/- entry is NOT optional, but  used by NG_CLONE to determine whether or');
  640.       writeln('  not to install itself as a resident program.');
  641.     end;
  642.   
  643.     procedure slutlort(b:byte);
  644.     {Exit on error and display relevant error message}
  645.     begin
  646.       if b>3 then close(f);
  647.       if b>2 then
  648.         begin
  649.           write('NG_CLONE ERROR #');write(b);writeln(': '+errorinfo[b]+', cannot proceed');
  650.         end;
  651.       if b<3 then usage;
  652.       halt(0);
  653.     end;
  654.   
  655.     procedure sllut(b:byte);
  656.     {Error handler without exit, just indicating the error type}
  657.       var sl:byte;
  658.     begin
  659.       if scrtypeflag=0 then sl:=startline else sl:=0;
  660.       if b>3 then close(f);
  661.       writestring(4,4+sl,Normal_Text,0,74,' '+errorinfo[b]+' - Press any key');
  662.       erro:=1;
  663.     end;
  664.   
  665.     function decrypt(b:byte):byte;
  666.     {Decrypt byte from NG format}
  667.     begin
  668.       if ((b and 31)>=16) then b:=b-16 else b:=b+16;
  669.       if ((b and 15)>=8) then b:=b-8 else b:=b+8;
  670.       if ((b and 3)>=2) then b:=b-2 else b:=b+2;
  671.       decrypt:=b;
  672.     end;
  673.   
  674.     function read_byte:byte;
  675.     {Read and decrypt byte}
  676.       var
  677.         tb:byte;
  678.         numread:word;
  679.     begin
  680.       blockread(f,tb,1,numread);
  681.       read_byte:=decrypt(tb);
  682.     end;
  683.   
  684.     function read_word:word;
  685.     {Read and decrypt word}
  686.       var
  687.         tw:word;
  688.  
  689.     begin
  690.       tw:=read_byte;
  691.       read_word:=tw + (word(read_byte) shl 8);
  692.     end;
  693.  
  694.     function read_long:longint;
  695.     {Read and decrypt longint}
  696.       var tl:longint;
  697.  
  698.     begin
  699.       tl:=read_word;
  700.       read_long:=tl + (longint(read_word) shl 16);
  701.     end;
  702.   
  703.     procedure read_menu;
  704.     {Read a menu structure into the menu buffer}
  705.       var items:word;
  706.     begin
  707.       mennu[menunr,0].filptr:=filepos(f)-2;
  708.       seek(f,filepos(f)+2);
  709.       items:=read_word;
  710.       itemlist[menunr]:=items;
  711.       seek(f,filepos(f)+20);
  712.       for i:=1 to items-1 do
  713.         begin
  714.           mennu[menunr,i].filptr:=read_long;
  715.         end;
  716.       i:=filepos(f);
  717.       inc(i,(items*8));
  718.       seek(f,i);
  719.       for i:=0 to items-1 do
  720.         begin
  721.           j:=0;
  722.           repeat
  723.             mennu[menunr,i].name[j+1]:=chr(read_byte);
  724.             inc(j);
  725.           until (mennu[menunr,i].name[j]=#0);
  726.           mennu[menunr,i].name[0]:=chr(j-1);
  727.           if j-1>menulengths[menunr+3] then menulengths[menunr+3]:=j-1;
  728.         end;
  729.       seek(f,filepos(f)+1);
  730.     end;
  731.   
  732.     procedure skip_short_long;        {Skip procedure for the initial menu seek}
  733.       var length:word;
  734.     begin
  735.       length:=read_word;
  736.       seek(f,filepos(f)+22+length);
  737.     end;
  738.   
  739.     procedure read_header(modf:byte);
  740.     {Read NG file header and enter the guide name in the screen template}
  741.       var guidenavn:string;
  742.         buf:array[0..377] of byte;
  743.         numread:word;
  744.     begin
  745.       blockread(f,buf,sizeof(buf),numread);
  746.       if ((buf[0]<>78) or (buf[1]<>71)) then
  747.  {If the two first characters in the file are not 'NG', the file is no guide}
  748.         begin
  749.           if modf=0 then slutlort(4) else sllut(4);
  750.         end;
  751.       menuantal:=buf[6];
  752.       i:=0;
  753.       repeat
  754.         guidenavn[i+1]:=chr(buf[i+8]);
  755.         inc(i);
  756.       until (buf[i+8]=0);
  757.       guidenavn[0]:=chr(i);
  758.       guidenavn:=' The Norton Guide to '+guidenavn+' ';
  759.       for i:=1 to length(guidenavn) do
  760.         begin
  761.           smallscreen[1,39-(length(guidenavn) div 2)+i].cha:=ord(guidenavn[i]);
  762.         end;
  763.       seek(f,378);
  764.     end;
  765.   
  766.     procedure read_menus(modf:byte);
  767.     {Initial menu seek, indexing the whole file}
  768.     begin
  769.       repeat
  770.         id:=read_word;
  771.         if id<2 then skip_short_long
  772.         else
  773.           if id=2 then
  774.             begin
  775.               read_menu;
  776.               inc(menunr);
  777.             end
  778.           else
  779.             if (id<>5) then
  780.               begin
  781.                 if (filesize(f)<>filepos(f)) then
  782.                   begin
  783.                     if modf=0 then slutlort(5) else sllut(5);        {NG file error}
  784.                   end
  785.                 else id:=5;
  786.               end;
  787.       until (id=5);
  788.       if (menunr<>menuantal) then
  789.         begin
  790.           if modf=0 then slutlort(6) else sllut(6);   {Incomplete file}
  791.         end;
  792.     end;
  793.   
  794.     procedure read_strings(totnum:word);
  795.     {Read null-terminated strings into scroll buffer}
  796.       var stringchar:byte;
  797.     begin
  798.       for i:=1 to totnum do
  799.         begin
  800.           j:=0;
  801.           repeat
  802.             stringchar:=read_byte;
  803.             inc(j);
  804.             scrollbuffer[i-1][j]:=chr(stringchar);
  805.           until stringchar=0;
  806.           scrollbuffer[i-1][0]:=chr(j-1);
  807.         end;
  808.       bufferlength:=totnum-1;
  809.       for j:=bufferlength+1 to 511 do scrollbuffer[j]:='';
  810.     end;
  811.   
  812.     procedure read_short_entry;
  813.     {Read short entry from file and wring some information out of it}
  814.       var items:word;
  815.     begin
  816.       seek(f,filepos(f)+2);
  817.       items:=read_word;
  818.       seek(f,filepos(f)+20);
  819.       for i:=1 to items do
  820.         begin
  821.           seek(f,filepos(f)+2);
  822.           infobuffer[i-1]:=read_long;
  823.         end;
  824.       read_strings(items);
  825.       entrytype:=1;
  826.     end;
  827.   
  828.     procedure read_long_entry;
  829.     {Read long entry information}
  830.       var linens,dlength,seealso_num:word;
  831.         prev,nxt:longint;
  832.         stringchar:byte;
  833.     begin
  834.       seek(f,filepos(f)+2);
  835.       linens:=read_word;
  836.       dlength:=read_word;
  837.       seek(f,filepos(f)+10);
  838.       prev:=read_long;
  839.       nxt:=read_long;
  840.       read_strings(linens);
  841.       if dlength<>0 then                                                        {If there are seealso entries, read them}
  842.         begin
  843.           seealso_num:=read_word;
  844.           for i:=1 to seealso_num do
  845.             begin
  846.               if i<21 then seealso[i-1].filptr:=read_long else seek(f,filepos(f)+4);
  847.             end;
  848.           for i:=1 to seealso_num do
  849.             begin
  850.               if i<21 then
  851.                 begin
  852.                   j:=0;
  853.                   repeat
  854.                     stringchar:=read_byte;
  855.                     inc(j);
  856.                     seealso[i-1].name[j]:=chr(stringchar);
  857.                   until stringchar=0;
  858.                   seealso[i-1].name[0]:=chr(j-1);
  859.                 end;
  860.             end;
  861.           seealsonum:=seealso_num-1;
  862.           if seealsonum>19 then seealsonum:=19;
  863.         end
  864.       else seealsonum:=255;
  865.       entrytype:=2;
  866.       previous:=prev;
  867.       next:=nxt;
  868.     end;
  869.   
  870.     procedure read_entry(fp:longint);
  871.     {Read some kind of file entry}
  872.     begin
  873.       seek(f,fp);
  874.       id:=read_word;
  875.       case id of
  876.       0:    read_short_entry;
  877.       1:    read_long_entry;
  878.       end;
  879.       if ((id=0) or (level=0)) then parent[level]:=fp;
  880.     end;
  881.   
  882.     procedure scrollinsert(addo_ins,directf:byte);
  883.     {Insert for the scroll procedure}
  884.       var sl:byte;
  885.     begin
  886.       if scrtypeflag=0 then sl:=startline else sl:=0;
  887.       if directf=0 then dec(offset) else inc(offset);
  888.       for i:=0 to addo_ins-1 do
  889.         begin
  890.           writestring(2,4+i+sl,Normal_Text,1,78,scrollbuffer[i+offset]);
  891.         end;
  892.     end;
  893.   
  894.     procedure scroll(direction:byte);
  895.     {Scroll text screen}
  896.       var addo,sl:byte;
  897.     begin
  898.       addo:=(scrtypeflag*13)+8;
  899.       if scrtypeflag=0 then sl:=startline else sl:=0;
  900.       if scrtypeflag=1 then inc(addo,lo(numrows)-24);
  901.       if entrytype=1 then
  902.         begin
  903.           removecursor;
  904.           if direction=0 then
  905.             begin
  906.               if curpos>0 then
  907.                 begin
  908.                   dec(curpos);
  909.                 end
  910.               else
  911.                 begin
  912.                   if offset>0 then scrollinsert(addo,0);
  913.                 end;
  914.             end
  915.           else
  916.             begin
  917.               if curpos<addo-1 then
  918.                 begin
  919.                   if curpos<bufferlength then
  920.                     begin
  921.                       inc(curpos);
  922.                     end;
  923.                 end
  924.               else
  925.                 begin
  926.                   if offset+addo<bufferlength+1 then scrollinsert(addo,1);
  927.                 end;
  928.             end;
  929.           insertcursor;
  930.         end
  931.       else
  932.         begin
  933.           if direction=0 then
  934.             begin
  935.               if offset>0 then scrollinsert(addo,0);
  936.             end
  937.           else
  938.             begin
  939.               if offset+addo<bufferlength+1 then scrollinsert(addo,1);
  940.             end;
  941.         end;
  942.       if curpos>7 then addo:=curpos-7 else addo:=0;
  943.       if scrtypeflag=0 then
  944.         for i:=4 to 11 do
  945.           for j:=2 to 79 do smallscreen[i,j]:=screen[i+startline,j]
  946.       else
  947.         for i:=4 to 11 do
  948.           for j:=2 to 79 do smallscreen[i,j]:=screen[i+addo,j];
  949.       if scrtypeflag=0
  950.         then j:=10
  951.       else
  952.         j:=lo(numrows)-1;
  953.       for i:=5 to j
  954.         do screen[i+sl,80].att:=$07;
  955.       i:=(((curpos+offset)*(j-4)) div (bufferlength+1))+5;
  956.       if i>j then i:=j;
  957.       screen[i+sl,80].att:=$40;
  958.     end;
  959.   
  960.     procedure keycommons;
  961.     {General screen repaint}
  962.     begin
  963.       if scrtypeflag=0 then
  964.         begin
  965.           makesmall(startline);
  966.           if entrytype=1 then removecursor;
  967.           i:=0;
  968.           while ((i<bufferlength+1) and (i<8)) do
  969.             begin
  970.               writestring(2,4+i+startline,Normal_Text,1,78,scrollbuffer[i+offset]);inc(i);
  971.             end;
  972.           if i<8 then for i:=i to 7 do
  973.               begin
  974.                 writestring(2,4+i+startline,Normal_Text,0,78,' ');
  975.               end;
  976.           for i:=4 to 11 do for j:=2 to 79 do smallscreen[i,j]:=screen[i+startline,j];
  977.           if entrytype=1 then insertcursor;
  978.         end
  979.       else
  980.         begin
  981.           makelarge;
  982.         end;
  983.     end;
  984.   
  985.     procedure pgup;
  986.     {Page up procedure for the text screen}
  987.       var addo:byte;
  988.     begin
  989.       addo:=(scrtypeflag*13)+8;
  990.       if scrtypeflag=1 then inc(addo,lo(numrows)-24);
  991.       if entrytype=1 then
  992.         begin
  993.           if curpos>0 then
  994.             begin
  995.               removecursor;
  996.               curpos:=1;
  997.             end
  998.           else
  999.             begin
  1000.               dec(offset,addo-2);
  1001.               if ((offset<1) or (offset>10000)) then offset:=1;
  1002.             end;
  1003.         end
  1004.       else
  1005.         begin
  1006.           curpos:=0;
  1007.           dec(offset,addo-2);
  1008.           if ((offset<1) or (offset>10000)) then offset:=1;
  1009.         end;
  1010.       scroll(0);
  1011.     end;
  1012.   
  1013.     procedure pgdn;
  1014.     {Page down procedure for the text screen}
  1015.       var addo:byte;
  1016.     begin
  1017.       addo:=(scrtypeflag*13)+8;
  1018.       if scrtypeflag=1 then inc(addo,lo(numrows)-24);
  1019.       if entrytype=1 then
  1020.         begin
  1021.           if curpos<addo-1 then
  1022.             begin
  1023.               removecursor;
  1024.               curpos:=addo-2;
  1025.               if curpos>bufferlength-1 then curpos:=bufferlength-1;
  1026.             end
  1027.           else
  1028.             begin
  1029.               inc(offset,addo-2);
  1030.               if offset+addo>bufferlength then offset:=bufferlength-addo;
  1031.             end;
  1032.         end
  1033.       else
  1034.         begin
  1035.           curpos:=addo-1;
  1036.           inc(offset,addo-2);
  1037.           if offset+addo>bufferlength then offset:=bufferlength-addo;
  1038.           if offset>10000 then offset:=0;
  1039.         end;
  1040.       scroll(1);
  1041.     end;
  1042.   
  1043.     procedure getstreng;
  1044.     {Read string from keyboard and echo it on screen}
  1045.       var chii:word;
  1046.         stl,sl:byte;
  1047.         chin:char;
  1048.     begin
  1049.       if scrtypeflag=0 then sl:=startline else sl:=0;
  1050.       streng:='';stl:=0;
  1051.       writestring(15,4+sl,Normal_Text+128,0,0,#219);
  1052.       repeat
  1053.         keyread(chii);chin:=chr(lo(chii));
  1054.         if ((31<chii) and (chii<256) and (length(streng)<62)) then
  1055.           begin
  1056.             writestring(15+stl,4+sl,Normal_Text,0,0,upcase(chin));
  1057.             streng:=streng+upcase(chin);
  1058.             inc(stl);
  1059.             writestring(15+stl,4+sl,Normal_Text+128,0,0,#219);
  1060.           end;
  1061.         if ((chii=8) and (length(streng)>0)) then
  1062.           begin
  1063.             writestring(15+stl,4+sl,Normal_Text,0,0,#0);
  1064.             streng:=copy(streng,1,length(streng)-1);
  1065.             dec(stl);
  1066.             writestring(15+stl,4+sl,Normal_Text+128,0,0,#219);
  1067.           end;
  1068.       until ((chii=13) or (chii=27));
  1069.       if chii=27 then streng:='';
  1070.     end;
  1071.   
  1072.     procedure s_o_l_insert;
  1073.     {Insert for the search-or-load procedure}
  1074.       var savl:byte;
  1075.     begin
  1076.       screen:=savedscreen;
  1077.       if scrtypeflag=1 then
  1078.         begin
  1079.           savl:=startline;
  1080.           startline:=0;
  1081.           createsmall;
  1082.           makelarge;
  1083.           startline:=savl;
  1084.         end
  1085.       else createsmall;
  1086.       insertcursor;
  1087.       makemenu(3);
  1088.     end;
  1089.   
  1090.     procedure exitmenus;
  1091.     {Remove pull-down menu}
  1092.       var add:byte;
  1093.     begin
  1094.       mlevel:=0;menuy:=0;wix:=0;wiy:=0;
  1095.       if scrtypeflag=0 then makesmall(startline) else
  1096.         begin
  1097.           for j:=1 to 80 do screen[3,j]:=smallscreen[3,j];
  1098.           i:=0;
  1099.           while ((i+offset<bufferlength+1) and (i<9)) do
  1100.             begin
  1101.               writestring(2,4+i,Normal_Text,1,78,scrollbuffer[i+offset]);inc(i);
  1102.             end;
  1103.           if entrytype=1 then insertcursor;
  1104.           for i:=5 to lo(numrows)-1 do screen[i,80].att:=$07;
  1105.           i:=(((curpos+offset)*(lo(numrows)-5)) div (bufferlength+1))+5;
  1106.           if i>lo(numrows)-1 then i:=lo(numrows)-1;
  1107.           screen[i,80].att:=$40;
  1108.         end;
  1109.     end;
  1110.   
  1111.     procedure search_or_load(typ:byte;namest:string);
  1112.     {Search for entry or load new NG file}
  1113.       var sl,savl:byte;
  1114.         tmpchr:word;
  1115.         savst:string;
  1116.     begin
  1117.       if scrtypeflag=0 then sl:=startline else sl:=0;
  1118.       wix:=2;wiy:=2+sl;
  1119.       frame1(76,3);
  1120.       writestring(4,4+sl,Normal_Text,0,74,namest);
  1121.       savst:=streng;
  1122.       getstreng;
  1123.       if streng<>'' then
  1124.         begin
  1125.           if typ=0 then
  1126.             begin
  1127. {SEARCH begins - feel free to add this yourself}
  1128.               if scrtypeflag=0 then
  1129.                 begin
  1130.                   makesmall(startline);
  1131.                 end
  1132.               else
  1133.                 begin
  1134.                   makelarge;
  1135.                 end;
  1136.               wix:=0;wiy:=0;
  1137. {SEARCH ends - feel free to add this yourself}
  1138.             end
  1139.           else
  1140.             begin
  1141.             {Load new guide file}
  1142.               erro:=0;
  1143.               if pos('.',streng)=0 then streng:=streng+'.NG';
  1144.               if ((pos('\',streng)=0) and (pos(':',streng)=0)) then
  1145.               writestring(4,4+sl,Normal_Text,0,74,' Loading '+homedir+streng+' - please wait') else
  1146.                 writestring(4,4+sl,Normal_Text,0,74,' Loading '+streng+' - please wait');
  1147.               close(f);
  1148.               twonitvars;
  1149.               if ((pos('\',streng)=0) and (pos(':',streng)=0)) then assign(f,homedir+streng) else assign(f,streng);
  1150.               reset(f,1);
  1151.               if ioresult<>0 then
  1152.                 begin
  1153.                   sllut(3);
  1154.                 end;
  1155.               if erro=0 then
  1156.                 begin
  1157.                   read_header(1);
  1158.                 end;
  1159.               if erro=0 then
  1160.                 begin
  1161.                   read_menus(1);
  1162.                 end;
  1163.               if erro=0 then
  1164.                 begin
  1165.                   read_entry(mennu[0,1].filptr);
  1166.                   s_o_l_insert;
  1167.                 end
  1168.               else
  1169.                 begin {If there are any errors, we reload the old guide file}
  1170.                   keyread(tmpchr);
  1171.                   streng:=savst;
  1172.                   twonitvars;
  1173.                   if ((pos('\',streng)=0) and (pos(':',streng)=0)) then
  1174.                   assign(f,homedir+streng) else assign(f,streng);
  1175.                   reset(f,1);
  1176.                   read_header(1);
  1177.                   read_menus(1);
  1178.                   read_entry(mennu[0,1].filptr);
  1179.                   s_o_l_insert;
  1180.                 end;
  1181.             end;
  1182.         end
  1183.       else exitmenus;
  1184.     end;
  1185.   
  1186.     procedure escape_insert;
  1187.     {Insert for the ESC key handler}
  1188.     begin
  1189.       dec(level);
  1190.       read_entry(parent[level]);
  1191.       if ((level>0) or (entrytype=1)) then
  1192.         begin
  1193.           curpos:=pcurpos[level];offset:=poffset[level];
  1194.         end;
  1195.       sapos:=0;
  1196.       keycommons;
  1197.       ch:=0;
  1198.     end;
  1199.   
  1200.     procedure keyhandler;
  1201.     {Reads key from keyboard and decides which action to take}
  1202.       var sl:byte;
  1203.         tmpchr,tmo,tmc:word;
  1204.     begin
  1205.       repeat
  1206.         keyread(ch);
  1207.         case ch of
  1208.         43:        begin {'+' key - moves small screen one line down}
  1209.             if scrtypeflag=0 then
  1210.               begin
  1211.                 if startline<lo(numrows)-11 then
  1212.                   begin
  1213.                     inc(startline);
  1214.                     for i:=startline+11 downto startline do
  1215.                       for j:=1 to 80 do
  1216.                         screen[i+1,j]:=screen[i,j];
  1217.                     for j:=1 to 80 do
  1218.                       screen[startline,j]:=savedscreen[startline,j];
  1219.                     if mlevel=1 then inc(wiy);
  1220.                   end;
  1221.               end;
  1222.           end;
  1223.         45:        begin {'-' key - moves small screen one line up}
  1224.             if scrtypeflag=0 then
  1225.               begin
  1226.                 if startline>0 then
  1227.                   begin
  1228.                     dec(startline);
  1229.                     for i:=startline to startline+11 do
  1230.                       for j:=1 to 80 do
  1231.                         screen[i+1,j]:=screen[i+2,j];
  1232.                     for j:=1 to 80 do
  1233.                       screen[13+startline,j]:=savedscreen[13+startline,j];
  1234.                     if mlevel=1 then dec(wiy);
  1235.                   end;
  1236.               end;
  1237.           end;
  1238.         328:    if mlevel=0 then scroll(0) else        {UpArrow key}
  1239.             begin
  1240.               removemlcursor;
  1241.               if menuy>0 then dec(menuy) else menuy:=itemlist[menux-3]-2;
  1242.               insertmlcursor;
  1243.             end;
  1244.         336:    if mlevel=0 then scroll(1) else        {DownArrow key}
  1245.             begin
  1246.               removemlcursor;
  1247.               if menuy<itemlist[menux-3]-2 then inc(menuy) else menuy:=0;
  1248.               insertmlcursor;
  1249.             end;
  1250.         329:    if mlevel=0 then pgup;    {PgUp key}
  1251.         337:    if mlevel=0 then pgdn;    {PgDn key}
  1252.         327:    if entrytype=2 then       {Home key - go to previous entry}
  1253.             begin
  1254.               if level>0 then
  1255.                 begin
  1256.                   if previous>0 then
  1257.                     begin
  1258.                       read_entry(previous);
  1259.                       curpos:=0;offset:=0;sapos:=0;
  1260.                       keycommons;
  1261.                     end;
  1262.                 end;
  1263.             end;
  1264.         335:    if entrytype=2 then       {End key - go to next entry}
  1265.             begin
  1266.               if level>0 then
  1267.                 begin
  1268.                   if next>0 then
  1269.                     begin
  1270.                       read_entry(next);
  1271.                       curpos:=0;offset:=0;sapos:=0;
  1272.                       keycommons;
  1273.                     end;
  1274.                 end;
  1275.             end;
  1276.         331:    if mlevel=0 then          {LeftArrow key}
  1277.             begin
  1278.               if ((entrytype=1) or (level=0)) then
  1279.                 movemenucursor(0)
  1280.               else
  1281.                 moveseealso(0);
  1282.             end
  1283.           else
  1284.             begin
  1285.               exitmenus;
  1286.               movemenucursor(0);
  1287.             end;
  1288.         333:    if mlevel=0 then          {RightArrow key}
  1289.             begin
  1290.               if ((entrytype=1) or (level=0)) then
  1291.                 movemenucursor(1)
  1292.               else
  1293.                 moveseealso(1);
  1294.             end
  1295.           else
  1296.             begin
  1297.               exitmenus;
  1298.               movemenucursor(1);
  1299.             end;
  1300.         9    :     begin {Tab key - toggles between small and large screens}
  1301.             if scrtypeflag=0 then
  1302.               begin
  1303.                 scrtypeflag:=1;
  1304.                 makelarge;
  1305.               end
  1306.             else
  1307.               begin
  1308.                 scrtypeflag:=0;
  1309.                 makesmall(startline);
  1310.                 if mlevel=1 then makemenu(menux);
  1311.               end;
  1312.           end;
  1313.         13:        if ((entrytype=1) or (level=0)) then
  1314.                 {ENTER key handler}
  1315.             begin
  1316.               if menux=0 then
  1317.                 begin
  1318.                   tmc:=curpos;tmo:=offset;
  1319.                   pcurpos[level]:=curpos;poffset[level]:=offset;
  1320.                   curpos:=0;offset:=0;
  1321.                   inc(level);
  1322.                   read_entry(infobuffer[tmc+tmo]);
  1323.                   keycommons;
  1324.                 end
  1325.               else if menux=1 then
  1326.                 begin
  1327.                   search_or_load(0,' Look for:');
  1328.                 end
  1329.               else if menux=2 then
  1330.                 begin
  1331.                   search_or_load(1,' New file:');
  1332.                 end
  1333.               else
  1334.                 begin
  1335.                   if mlevel=0 then makemenu(menux)
  1336.                   else
  1337.                     begin
  1338.                       read_entry(mennu[menux-3,menuy+1].filptr);
  1339.                       if entrytype=2 then inc(level);
  1340.                       xchoice:=menux-3;ychoice:=menuy;
  1341.                       curpos:=0;offset:=0;mlevel:=0;menuy:=0;
  1342.                       keycommons;
  1343.                     end;
  1344.                 end;
  1345.             end
  1346.           else
  1347.             begin
  1348.               if seealsonum<>255 then
  1349.                 begin
  1350.                   read_entry(seealso[sapos].filptr);
  1351.                   curpos:=0;offset:=0;sapos:=0;
  1352.                   keycommons;
  1353.                 end;
  1354.             end;
  1355.         27:        if ((entrytype=2) and (level>0)) then        {ESC key handler}
  1356.             begin
  1357.               escape_insert;
  1358.             end
  1359.           else if mlevel=1 then
  1360.             begin
  1361.               exitmenus;
  1362.               ch:=0;
  1363.             end
  1364.           else
  1365.             begin
  1366.               if level>0 then
  1367.                 begin
  1368.                   escape_insert;
  1369.                 end
  1370.               else
  1371.                 begin
  1372.                   if scrtypeflag=0 then sl:=startline else sl:=0;
  1373.                   wix:=2;wiy:=2+sl;
  1374.                   frame1(40,3);
  1375.                   writestring(4,4+sl,Bold_Face,0,38,' Do you really want to quit (Y/N) ?');
  1376.                   repeat
  1377.                     keyread(tmpchr);
  1378.                   until ((upcase(chr(lo(tmpchr)))='Y') or (upcase(chr(lo(tmpchr)))='N'));
  1379.                   writestring(40,4+sl,Bold_Face,0,0,upcase(chr(lo(tmpchr))));
  1380.                   i:=0;while i<65535 do inc(i);
  1381.                   if upcase(chr(lo(tmpchr)))='N' then
  1382.                     begin
  1383.                       if scrtypeflag=0 then makesmall(startline) else makelarge;
  1384.                       ch:=0;
  1385.                     end;
  1386.                 end;
  1387.             end;
  1388.         end;
  1389.       until ch=27;
  1390.     end;
  1391.   
  1392.     function sizeofcode:word;          {TESS function to decide size of
  1393.                                         resident code}
  1394.       var used:word;
  1395.     begin
  1396.       used:=seg(heapptr^)-prefixseg;
  1397.       sizeofcode:=used;
  1398.     end;
  1399.   
  1400. {$F+} procedure tsrmainproc; {$F-}     {TESS resident procedure entry point}
  1401.     begin
  1402.       if ((lo(screenmode)<4) or (lo(screenmode)=7)) then
  1403.         begin
  1404.           savedcsr:=csr;
  1405.           threenitvars;
  1406.           startline:=0;
  1407.           scrtypeflag:=0;
  1408.           read_entry(mennu[0,1].filptr);
  1409.           createsmall;
  1410.           insertcursor;
  1411.           makemenu(3);
  1412.           keyhandler;
  1413.           screen:=savedscreen;
  1414.           if restorecrsr(savedcsr) then i:=i;
  1415.         end
  1416.       else
  1417.         begin
  1418.           tessbeep;
  1419.         end;
  1420.     end;
  1421.   
  1422. {$F+} procedure tsrcleanup(removetsr:boolean); {$F-}
  1423. {TESS install-or-remove procedure entry point}
  1424.     begin
  1425.       if (removetsr) then
  1426.         begin
  1427.           close(f);
  1428.           erroraddr:=NIL;
  1429.         end
  1430.       else
  1431.         begin
  1432.           initscreen;
  1433.           read_header(0);
  1434.           read_menus(0);
  1435.           write('NG_CLONE installed                                            Hotkey: Ctrl-Alt-G');
  1436.         end;
  1437.     end;
  1438.  
  1439. {
  1440. ++ Main Loop and Command-Line parser
  1441. }
  1442.  
  1443.   begin
  1444.     directvideo:=true;           {Force write and writeln direct to screen}
  1445.     writeln('┌────────────────────────────┐');
  1446.     writeln('│ Norton Guides Clone V. 1.1 │');
  1447.     writeln('│   (c) 1989 J.P.Pedersen    │');
  1448.     writeln('└────────────────────────────┘');
  1449.     initvars;                                                                        {Initialize global variables}
  1450.     tsrstring:='NG_CLONE';        {TESS ID string - rather original, eh?}
  1451.     tssetadrtp4(@tsrmainproc,2);  {Set TESS entry point}
  1452.     tssetadrtp4(@tsrcleanup,5);   {Set TESS entry point}
  1453.     defptr:=NIL;                                                                {TESS stack pointer #1}
  1454.     stackptr:=@backstack[(sizeof(backstack)-3)];        {TESS stack pointer #2}
  1455.     tssetstack(defptr^,stackptr^);            {Initialize TESS stacks}
  1456.     if (tscheckresident(tsrstring[1],idnum)=$FFFF) then        {Is NG_CLONE already resident?}
  1457.       begin
  1458.         if ((paramstr(1)='/U') or (paramstr(1)='/u')) then  {If uninstall command, then do so}
  1459.           begin
  1460.             writeln('NG_CLONE removed from memory');
  1461.             i:=tsrelease(idnum);
  1462.             halt(0);
  1463.           end
  1464.         else
  1465.           begin {Else report presence and exit}
  1466.             write('NG_CLONE already installed                                    Hotkey: Ctrl-Alt-G');
  1467.             halt(0);
  1468.           end;
  1469.       end
  1470.     else
  1471.       begin                                                                                                    {Else}
  1472.         if ((paramstr(1)='/U') or (paramstr(1)='/u')) then {If program is not resident, it cannot be removed!}
  1473.           begin
  1474.             writeln('NG_CLONE has not been installed!');
  1475.             halt(0);
  1476.           end;
  1477.       end;
  1478.     if ((paramstr(1)='/?') or (paramstr(1)='/h') or (paramstr(1)='/H')) then slutlort(0);        {Write usage info and exit}
  1479.     if paramcount<2 then slutlort(1);         {Command-line syntax error}
  1480.     if paramcount>3 then slutlort(2);         {Command-line syntax error}
  1481.     streng:=paramstr(1);
  1482.     if paramcount=3 then homedir:=paramstr(2)+'\' else homedir:='';        {Check for ngdir entry on command-line}
  1483.     if pos('.',streng)=0 then streng:=streng+'.NG';        {Expand file name}
  1484.     if ((pos('\',streng)=0) and (pos(':',streng)=0)) then assign(f,homedir+streng) else assign(f,streng); {Expand further}
  1485.     reset(f,1);
  1486.     if ioresult<>0 then slutlort(3);                        {If file does not exist, terminate and write cause of death}
  1487.     if (paramstr(paramcount)='+') then                    {Should we go resident?}
  1488.       begin {OK, we let TESS do the hard work}
  1489.         if (tsdoinit(tsrhot_g,tsrpopalt+tsrpopctrl,tsrusepopup,sizeofcode)<>0) then writeln('Cannot install');
  1490.       end
  1491.     else if (paramstr(paramcount)='-') then
  1492.     {Non-resident mode wanted}
  1493.       begin
  1494.         savedcsr:=csr;
  1495.         initscreen;
  1496.         read_header(0);
  1497.         read_menus(0);
  1498.         read_entry(mennu[0,1].filptr);
  1499.         createsmall;
  1500.         insertcursor;
  1501.         makemenu(3);
  1502.         keyhandler;
  1503.         screen:=savedscreen;
  1504.         close(f);
  1505.         if restorecrsr(savedcsr) then i:=i;
  1506.       end
  1507.     else slutlort(0);
  1508.     {If there is no (+/-) switch to determine mode , it is an error}
  1509.     end.
  1510.